﻿#pragma once

#include <cassert>
#include <algorithm>
#include <mutex>
#include <memory>

#define MAX_BYTES_COUNT (1 << 18) // 单次从内存池中申请的最大内存 256KB
#define MIN_BATCH_COUNT 1   // 所获取内存块的批量下限
#define MAX_BATCH_COUNT 512 // 所获取内存块的批量上限
#define MAX_BARREL_COUNT 208 // thread cache与central cache的最大桶数
#define MAX_PAGES_COUNT 129  // 单个span的最大页数
#define UNIT_PAGE_SHIFT 13 // 一页的大小8KB

size_t Align(size_t sizeByte);  // 获取对齐字节
size_t Index(size_t alignByte); // 对齐后内存块所挂载索引位置

unsigned BatchNum(size_t alignByte); // 计算获取内存的批量

static inline void*& NextMemoryAddr(void* ptr) { return *(void**)ptr; } // 指针ptr前4/8个字节的信息

void* SystemAlloc(size_t kpage); // 从系统中按页申请内存
void SystemFree(void* ptr); // 释放内存

typedef unsigned long long PAGE_ID; // 页号
typedef unsigned int PAGE_NUM; // 页数

PAGE_NUM PagesNum(size_t sizeBytes); // 计算所获取Span的最小页数
static inline PAGE_ID AddrToPageID(void* addr) { return (PAGE_ID)addr >> UNIT_PAGE_SHIFT; } // 地址 -> 页号
static inline void* PageIDToAddr(PAGE_ID pageId) { return (void*)(pageId << UNIT_PAGE_SHIFT); } // 页号->地址

class nocopy // 不可拷贝
{
public:
	nocopy() = default;
	nocopy(const nocopy&) = delete;
	nocopy& operator=(const nocopy&) = delete;
};

class FreeList // 管理小块内存的自由链表
{
public:
	void clear();
	void push_front(void* obj);
	void pop_front();
	void* front() const;
	bool empty() const;
	size_t size() const;
private:
	void* _freelist = nullptr;
	size_t _size = 0;
};

class Span  // 大块内存的信息描述
{
public:
	PAGE_ID _page_id = 0;
	PAGE_NUM _page_len = 0;

	bool _use_if = false; // 是否正在使用(挂载在CentralCache位置即算使用)
	unsigned _size = 0;// 记录该Span切割后小块内存的大小
	unsigned _use_count = 0; // 正在使用的小块个数

	FreeList _freelist; // 对(由span平均分割后)小块内存的管理;
	Span* _prev = nullptr; // 前一个大块内存的地址
	Span* _next = nullptr; // 下一个大块内存的地址
};

class SpanList // 大块内存的管理 
{
public:
	static void erase(Span* span); // 将span从所属的带头双向循环链表中剥离出来

	SpanList()
	{
		_head = new Span;
		_head->_prev = _head;
		_head->_next = _head;
	}

	bool empty();
	Span* front();
	Span* GetNoEmptySpan();
	void pop_front();
	void push_front(Span* obj);

private:
	Span* _head; // 头指针
};

template<class T>
class ObjectPool // 定长内存池
{
public:
	T* alloc() // 仅完成内存申请
	{
		std::lock_guard<std::mutex> lock(_mtx);

		// 优先把还回来内存块对象，再次重复利用
		if (_freelist.empty() == false)
		{
			T* obj = (T*)_freelist.front();
			_freelist.pop_front();
			return obj;
		}
		else
		{
			// 剩余内存不够一个对象大小时，则重新开大块空间
			if (_remainBytes < sizeof(T))
			{
				_remainBytes = 131072; // 128字节
				_memory = (char*)SystemAlloc(_remainBytes >> UNIT_PAGE_SHIFT);
				if (_memory == nullptr)
					throw std::bad_alloc();
			}

			T* obj = (T*)_memory;
			size_t objSize = sizeof(T) >= sizeof(void*) ? sizeof(T) : sizeof(void*);

			_memory += objSize;
			_remainBytes -= objSize;

			return obj;
		}
	}
	void free(T* obj)
	{
		std::lock_guard<std::mutex> lock(_mtx);
		_freelist.push_front((void*)obj);
	}

	T* New() // 完成内存申请 + 对象初始化
	{
		T* obj = alloc();
		new(obj)T;

		return obj;
	}
	void Delete(T* obj) // 完成内存释放 + 对象销毁
	{
		obj->~T();
		free(obj);
	}

private:
	char* _memory = nullptr; // 指向大块内存的指针
	size_t _remainBytes = 0; // 大块内存在切分过程中剩余字节数
	FreeList _freelist; // 自由链表,管理还回来的小块内存
	std::mutex _mtx; // 互斥锁
};
